home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / perl5 / MLDBM.pm < prev    next >
Text File  |  2002-07-08  |  16KB  |  553 lines

  1. #
  2. # MLDBM.pm
  3. #
  4. # store multi-level hash structure in single level tied hash (read DBM)
  5. #
  6. # Documentation at the __END__
  7. #
  8. # Gurusamy Sarathy <gsar@umich.edu>
  9. # Raphael Manfredi <Raphael_Manfredi@grenoble.hp.com>
  10. #
  11.  
  12. require 5.004;
  13. use strict;
  14.  
  15. ####################################################################
  16. package MLDBM::Serializer;    ## deferred
  17.  
  18. use Carp;
  19.  
  20. #
  21. # The serialization interface comprises of just three methods:
  22. # new(), serialize() and deserialize().  Only the last two are
  23. # _required_ to be implemented by any MLDBM serialization wrapper.
  24. #
  25.  
  26. sub new { bless {}, shift };
  27.  
  28. sub serialize { confess "deferred" };
  29.  
  30. sub deserialize { confess "deferred" };
  31.  
  32.  
  33. #
  34. # Attributes:
  35. #
  36. #    dumpmeth:
  37. #    the preferred dumping method.
  38. #
  39. #    removetaint:
  40. #    untainting flag; when true, data will be untainted after
  41. #    extraction from the database.
  42. #
  43. #    key:
  44. #    the magic string used to recognize non-natively stored data.
  45. #
  46. # Attribute access methods:
  47. #
  48. #    These defaults allow readonly access. Sub-class may override
  49. #    them to allow write access if any of these attributes
  50. #    makes sense for it.
  51. #
  52.  
  53. sub DumpMeth    {
  54.     my $s = shift;
  55.     confess "can't set dumpmeth with " . ref($s) if @_;
  56.     $s->_attrib('dumpmeth');
  57. }
  58.  
  59. sub RemoveTaint    {
  60.     my $s = shift;
  61.     confess "can't set untaint with " . ref($s) if @_;
  62.     $s->_attrib('removetaint');
  63. }
  64.  
  65. sub Key    {
  66.     my $s = shift;
  67.     confess "can't set key with " . ref($s) if @_;
  68.     $s->_attrib('key');
  69. }
  70.  
  71. sub _attrib {
  72.     my ($s, $a, $v) = @_;
  73.     if (ref $s and @_ > 2) {
  74.     $s->{$a} = $v;
  75.     return $s;
  76.     }
  77.     $s->{$a};
  78. }
  79.  
  80. ####################################################################
  81. package MLDBM;
  82.  
  83. $MLDBM::VERSION = $MLDBM::VERSION = '2.01';
  84.  
  85. require Tie::Hash;
  86. @MLDBM::ISA = 'Tie::Hash';
  87.  
  88. use Carp;
  89.  
  90. #
  91. # the DB package to use (we default to SDBM since it comes with perl)
  92. # you might want to change this default to something more efficient
  93. # like DB_File (you can always override it in the use list)
  94. #
  95. $MLDBM::UseDB        = "SDBM_File"        unless $MLDBM::UseDB;
  96. $MLDBM::Serializer    = 'Data::Dumper'    unless $MLDBM::Serializer;
  97. $MLDBM::Key        = '$MlDbM'        unless $MLDBM::Key;
  98. $MLDBM::DumpMeth    = ""            unless $MLDBM::DumpMeth;
  99. $MLDBM::RemoveTaint    = 0            unless $MLDBM::RemoveTaint;
  100.  
  101. #
  102. # A private way to load packages at runtime.
  103. my $loadpack = sub {
  104.     my $pack = shift;
  105.     $pack =~ s|::|/|g;
  106.     $pack .= ".pm";
  107.     eval { require $pack };
  108.     if ($@) {
  109.     carp "MLDBM error: " . 
  110.       "Please make sure $pack is a properly installed package.\n" .
  111.         "\tPerl says: \"$@\"";
  112.     return undef;
  113.     }
  114.     1;
  115. };
  116.  
  117.  
  118. #
  119. # TIEHASH interface methods
  120. #
  121. sub TIEHASH {
  122.     my $c = shift;
  123.     my $s = bless {}, $c;
  124.  
  125.     #
  126.     # Create the right serializer object.
  127.     my $szr = $MLDBM::Serializer;
  128.     unless (ref $szr) {
  129.     $szr = "MLDBM::Serializer::$szr"    # allow convenient short names
  130.       unless $szr =~ /^MLDBM::Serializer::/;
  131.     &$loadpack($szr) or return undef;
  132.     $szr = $szr->new($MLDBM::DumpMeth,
  133.              $MLDBM::RemoveTaint,
  134.              $MLDBM::Key);
  135.     }
  136.     $s->Serializer($szr);
  137.  
  138.     #
  139.     # Create the right TIEHASH  object.
  140.     my $db = $MLDBM::UseDB;
  141.     unless (ref $db) {
  142.     &$loadpack($db) or return undef;
  143.     $db = $db->TIEHASH(@_)
  144.       or carp "MLDBM error: Second level tie failed, \"$!\""
  145.         and return undef;
  146.     }
  147.     $s->UseDB($db);
  148.  
  149.     return $s;
  150. }
  151.  
  152. sub FETCH {
  153.     my ($s, $k) = @_;
  154.     my $ret = $s->{DB}->FETCH($k);
  155.     $s->{SR}->deserialize($ret);
  156. }
  157.  
  158. sub STORE {
  159.     my ($s, $k, $v) = @_;
  160.     $v = $s->{SR}->serialize($v);
  161.     $s->{DB}->STORE($k, $v);
  162. }
  163.  
  164. sub DELETE    { my $s = shift; $s->{DB}->DELETE(@_); }
  165. sub FIRSTKEY    { my $s = shift; $s->{DB}->FIRSTKEY(@_); }
  166. sub NEXTKEY    { my $s = shift; $s->{DB}->NEXTKEY(@_); }
  167. sub EXISTS    { my $s = shift; $s->{DB}->EXISTS(@_); }
  168. sub CLEAR    { my $s = shift; $s->{DB}->CLEAR(@_); }
  169.  
  170. sub new        { &TIEHASH }
  171.  
  172. #
  173. # delegate messages to the underlying DBM
  174. #
  175. sub AUTOLOAD {
  176.     return if $MLDBM::AUTOLOAD =~ /::DESTROY$/;
  177.     my $s = shift;
  178.     if (ref $s) {            # twas a method call
  179.     my $dbname = ref($s->{DB});
  180.     # permit inheritance
  181.     $MLDBM::AUTOLOAD =~ s/^.*::([^:]+)$/$dbname\:\:$1/;
  182.     $s->{DB}->$MLDBM::AUTOLOAD(@_);
  183.     }
  184. }
  185.  
  186. #
  187. # delegate messages to the underlying Serializer
  188. #
  189. sub DumpMeth    { my $s = shift; $s->{SR}->DumpMeth(@_); }
  190. sub RemoveTaint    { my $s = shift; $s->{SR}->RemoveTaint(@_); }
  191. sub Key        { my $s = shift; $s->{SR}->Key(@_); }
  192.  
  193. #
  194. # get/set the DB object
  195. #
  196. sub UseDB     { my $s = shift; @_ ? ($s->{DB} = shift) : $s->{DB}; }
  197.  
  198. #
  199. # get/set the Serializer object
  200. #
  201. sub Serializer    { my $s = shift; @_ ? ($s->{SR} = shift) : $s->{SR}; }
  202.  
  203. #
  204. # stuff to do at 'use' time
  205. #
  206. sub import {
  207.     my ($pack, $dbpack, $szr, $dumpmeth, $removetaint, $key) = @_;
  208.     $MLDBM::UseDB = $dbpack if defined $dbpack and $dbpack;
  209.     $MLDBM::Serializer = $szr if defined $szr and $szr;
  210.     # undocumented, may change!
  211.     $MLDBM::DumpMeth = $dumpmeth if defined $dumpmeth;
  212.     $MLDBM::RemoveTaint = $removetaint if defined $removetaint;
  213.     $MLDBM::Key = $key if defined $key and $key;
  214. }
  215.  
  216. # helper subroutine for tests to compare to arbitrary data structures
  217. # for equivalency
  218. sub _compare {
  219.     use vars qw(%compared);
  220.     local %compared;
  221.     return _cmp(@_);
  222. }
  223.  
  224. sub _cmp {
  225.     my($a, $b) = @_;
  226.  
  227.     # catch circular loops
  228.     return(1) if $compared{$a.'&*&*&*&*&*'.$b}++;
  229. #    print "$a $b\n";
  230. #    print &Data::Dumper::Dumper($a, $b);
  231.  
  232.     if(ref($a) and ref($a) eq ref($b)) {
  233.     if(eval { @$a }) {
  234. #        print "HERE ".@$a." ".@$b."\n";
  235.         @$a == @$b or return 0;
  236. #        print @$a, ' ', @$b, "\n";
  237. #        print "HERE2\n";
  238.  
  239.         for(0..@$a-1) {
  240.         &_cmp($a->[$_], $b->[$_]) or return 0;
  241.         }
  242.     } elsif(eval { %$a }) {
  243.         keys %$a == keys %$b or return 0;
  244.         for (keys %$a) {
  245.         &_cmp($a->{$_}, $b->{$_}) or return 0;
  246.         }
  247.     } elsif(eval { $$a }) {
  248.         &_cmp($$a, $$b) or return 0;
  249.     } else {
  250.         die("data $a $b not handled");
  251.     }
  252.     return 1;
  253.     } elsif(! ref($a) and ! ref($b)) {
  254.     return ($a eq $b);
  255.     } else {
  256.     return 0;
  257.     }
  258.  
  259. }
  260.  
  261. 1;
  262.  
  263. __END__
  264.  
  265. =head1 NAME
  266.  
  267. MLDBM - store multi-level hash structure in single level tied hash
  268.  
  269. =head1 SYNOPSIS
  270.  
  271.     use MLDBM;                # this gets the default, SDBM
  272.     #use MLDBM qw(DB_File FreezeThaw);    # use FreezeThaw for serializing
  273.     #use MLDBM qw(DB_File Storable);    # use Storable for serializing
  274.     
  275.     $dbm = tie %o, 'MLDBM' [..other DBM args..] or die $!;
  276.  
  277. =head1 DESCRIPTION
  278.  
  279. This module can serve as a transparent interface to any TIEHASH package
  280. that is required to store arbitrary perl data, including nested references.
  281. Thus, this module can be used for storing references and other arbitrary data
  282. within DBM databases.
  283.  
  284. It works by serializing the references in the hash into a single string. In the
  285. underlying TIEHASH package (usually a DBM database), it is this string that
  286. gets stored.  When the value is fetched again, the string is deserialized to
  287. reconstruct the data structure into memory.
  288.  
  289. For historical and practical reasons, it requires the B<Data::Dumper> package,
  290. available at any CPAN site. B<Data::Dumper> gives you really nice-looking dumps of
  291. your data structures, in case you wish to look at them on the screen, and
  292. it was the only serializing engine before version 2.00.  However, as of version
  293. 2.00, you can use any of B<Data::Dumper>, B<FreezeThaw> or B<Storable> to
  294. perform the underlying serialization, as hinted at by the L<SYNOPSIS> overview
  295. above.  Using B<Storable> is usually much faster than the other methods.
  296.  
  297. See the L<BUGS> section for important limitations.
  298.  
  299. =head2 Changing the Defaults
  300.  
  301. B<MLDBM> relies on an underlying TIEHASH implementation (usually a
  302. DBM package), and an underlying serialization package.  The respective
  303. defaults are B<SDBM_File> and B<Data::Dumper>.  Both of these defaults
  304. can be changed.  Changing the B<SDBM_File> default is strongly recommended.
  305. See L<WARNINGS> below.
  306.  
  307. Three serialization wrappers are currently supported: B<Data::Dumper>,
  308. B<Storable>, and B<FreezeThaw>.  Additional serializers can be
  309. supported by writing a wrapper that implements the interface required by
  310. B<MLDBM::Serializer>.  See the supported wrappers and the B<MLDBM::Serializer>
  311. source for details.
  312.  
  313. In the following, I<$OBJ> stands for the tied object, as in:
  314.  
  315.     $obj = tie %o, ....
  316.     $obj = tied %o;
  317.  
  318. =over 4
  319.  
  320. =item $MLDBM::UseDB    I<or>    I<$OBJ>->UseDB(I<[TIEDOBJECT]>)
  321.  
  322. The global C<$MLDBM::UseDB> can be set to default to something other than
  323. C<SDBM_File>, in case you have a more efficient DBM, or if you want to use
  324. this with some other TIEHASH implementation.  Alternatively, you can specify
  325. the name of the package at C<use> time, as the first "parameter".
  326. Nested module names can be specified as "Foo::Bar".
  327.  
  328. The corresponding method call returns the underlying TIEHASH object when
  329. called without arguments.  It can be called with any object that
  330. implements Perl's TIEHASH interface, to set that value.
  331.  
  332. =item $MLDBM::Serializer    I<or>    I<$OBJ>->Serializer(I<[SZROBJECT]>)
  333.  
  334. The global C<$MLDBM::Serializer> can be set to the name of the serializing
  335. package to be used. Currently can be set to one of C<Data::Dumper>,
  336. C<Storable>, or C<FreezeThaw>. Defaults to C<Data::Dumper>.  Alternatively,
  337. you can specify the name of the serializer package at C<use> time, as the
  338. second "parameter".
  339.  
  340. The corresponding method call returns the underlying MLDBM serializer object
  341. when called without arguments.  It can be called with an object that
  342. implements the MLDBM serializer interface, to set that value.
  343.  
  344. =back
  345.  
  346. =head2 Controlling Serializer Properties
  347.  
  348. These methods are meant to supply an interface to the properties of the
  349. underlying serializer used.  Do B<not> call or set them without
  350. understanding the consequences in full.  The defaults are usually sensible.
  351.  
  352. Not all of these necessarily apply to all the supplied serializers, so we
  353. specify when to apply them.  Failure to respect this will usually lead to
  354. an exception.
  355.  
  356. =over 4
  357.  
  358. =item $MLDBM::DumpMeth    I<or>  I<$OBJ>->DumpMeth(I<[METHNAME]>)
  359.  
  360. If the serializer provides alternative serialization methods, this
  361. can be used to set them.
  362.  
  363. With B<Data::Dumper> (which offers a pure Perl and an XS verion
  364. of its serializing routine), this is set to C<Dumpxs> by default if that
  365. is supported in your installation.  Otherwise, defaults to the slower
  366. C<Dump> method.
  367.  
  368. With B<Storable>, a value of C<portable> requests that serialization be
  369. architecture neutral, i.e. the deserialization can later occur on another
  370. platform. Of course, this only makes sense if your database files are
  371. themselves architecture neutral.  By default, native format is used for
  372. greater serializing speed in B<Storable>.  Both B<Data::Dumper> and
  373. B<FreezeThaw> are always architecture neutral.
  374.  
  375. B<FreezeThaw> does not honor this attribute.
  376.  
  377. =item $MLDBM::Key  I<or>  I<$OBJ>->Key(I<[KEYSTRING]>)
  378.  
  379. If the serializer only deals with part of the data (perhaps because
  380. the TIEHASH object can natively store some types of data), it may need
  381. a unique key string to recognize the data it handles.  This can be used
  382. to set that string.  Best left alone.
  383.  
  384. Defaults to the magic string used to recognize MLDBM data. It is a six
  385. character wide, unique string. This is best left alone, unless you know
  386. what you are doing. 
  387.  
  388. B<Storable> and B<FreezeThaw> do not honor this attribute.
  389.  
  390. =item $MLDBM::RemoveTaint  I<or>  I<$OBJ>->RemoveTaint(I<[BOOL]>)
  391.  
  392. If the serializer can optionally untaint any retrieved data subject to
  393. taint checks in Perl, this can be used to request that feature.  Data
  394. that comes from external sources (like disk-files) must always be
  395. viewed with caution, so use this only when you are sure that that is
  396. not an issue.
  397.  
  398. B<Data::Dumper> uses C<eval()> to deserialize and is therefore subject to
  399. taint checks.  Can be set to a true value to make the B<Data::Dumper>
  400. serializer untaint the data retrieved. It is not enabled by default.
  401. Use with care.
  402.  
  403. B<Storable> and B<FreezeThaw> do not honor this attribute.
  404.  
  405. =back
  406.  
  407. =head1 EXAMPLES
  408.  
  409. Here is a simple example.  Note that does not depend upon the underlying
  410. serializing package--most real life examples should not, usually.
  411.  
  412.     use MLDBM;                # this gets SDBM and Data::Dumper
  413.     #use MLDBM qw(SDBM_File Storable);    # SDBM and Storable
  414.     use Fcntl;                # to get 'em constants
  415.      
  416.     $dbm = tie %o, 'MLDBM', 'testmldbm', O_CREAT|O_RDWR, 0640 or die $!;
  417.     
  418.     $c = [\ 'c'];
  419.     $b = {};
  420.     $a = [1, $b, $c];
  421.     $b->{a} = $a;
  422.     $b->{b} = $a->[1];
  423.     $b->{c} = $a->[2];
  424.     @o{qw(a b c)} = ($a, $b, $c);
  425.     
  426.     #
  427.     # to see what was stored
  428.     #
  429.     use Data::Dumper;
  430.     print Data::Dumper->Dump([@o{qw(a b c)}], [qw(a b c)]);
  431.     
  432.     #
  433.     # to modify data in a substructure
  434.     #
  435.     $tmp = $o{a};
  436.     $tmp->[0] = 'foo';
  437.     $o{a} = $tmp;
  438.     
  439.     #
  440.     # can access the underlying DBM methods transparently
  441.     #
  442.     #print $dbm->fd, "\n";        # DB_File method
  443.  
  444. Here is another small example using Storable, in a portable format:
  445.  
  446.     use MLDBM qw(DB_File Storable);    # DB_File and Storable
  447.     
  448.     tie %o, 'MLDBM', 'testmldbm', O_CREAT|O_RDWR, 0640 or die $!;
  449.     
  450.     (tied %o)->DumpMeth('portable');    # Ask for portable binary
  451.     $o{'ENV'} = \%ENV;            # Stores the whole environment
  452.     
  453.  
  454. =head1 BUGS
  455.  
  456. =over 4
  457.  
  458. =item 1.
  459.  
  460. Adding or altering substructures to a hash value is not entirely transparent
  461. in current perl.  If you want to store a reference or modify an existing
  462. reference value in the DBM, it must first be retrieved and stored in a
  463. temporary variable for further modifications.  In particular, something like
  464. this will NOT work properly:
  465.  
  466.     $mldb{key}{subkey}[3] = 'stuff';    # won't work
  467.  
  468. Instead, that must be written as:
  469.  
  470.     $tmp = $mldb{key};            # retrieve value
  471.     $tmp->{subkey}[3] = 'stuff';
  472.     $mldb{key} = $tmp;            # store value
  473.  
  474. This limitation exists because the perl TIEHASH interface currently has no
  475. support for multidimensional ties.
  476.  
  477. =item 2.
  478.  
  479. The B<Data::Dumper> serializer uses eval().  A lot.  Try the B<Storable>
  480. serializer, which is generally the most efficient.
  481.  
  482. =back
  483.  
  484. =head1 WARNINGS
  485.  
  486. =over 4
  487.  
  488. =item 1.
  489.  
  490. Many DBM implementations have arbitrary limits on the size of records
  491. that can be stored.  For example, SDBM and many ODBM or NDBM
  492. implementations have a default limit of 1024 bytes for the size of a
  493. record.  MLDBM can easily exceed these limits when storing large data
  494. structures, leading to mysterious failures.  Although SDBM_File is
  495. used by MLDBM by default, it is not a good choice if you're storing
  496. large data structures.  Berkeley DB and GDBM both do not have these
  497. limits, so I recommend using either of those instead.
  498.  
  499. =item 2.
  500.  
  501. MLDBM does well with data structures that are not too deep and not
  502. too wide.  You also need to be careful about how many C<FETCH>es your
  503. code actually ends up doing.  Meaning, you should get the most mileage
  504. out of a C<FETCH> by holding on to the highest level value for as long
  505. as you need it.  Remember that every toplevel access of the tied hash,
  506. for example C<$mldb{foo}>, translates to a MLDBM C<FETCH()> call.
  507.  
  508. Too often, people end up writing something like this:
  509.  
  510.         tie %h, 'MLDBM', ...;
  511.         for my $k (keys %{$h{something}}) {
  512.             print $h{something}{$k}[0]{foo}{bar};  # FETCH _every_ time!
  513.         }
  514.  
  515. when it should be written this for efficiency:
  516.  
  517.         tie %h, 'MLDBM', ...;
  518.         my $root = $h{something};                  # FETCH _once_
  519.         for my $k (keys %$root) {
  520.             print $k->[0]{foo}{bar};
  521.         }
  522.  
  523.  
  524. =back
  525.  
  526. =head1 AUTHORS
  527.  
  528. Gurusamy Sarathy <F<gsar@umich.edu>>.
  529.  
  530. Support for multiple serializing packages by
  531. Raphael Manfredi <F<Raphael_Manfredi@grenoble.hp.com>>.
  532.  
  533. Test suite fixes for perl 5.8.0 done by Josh Chamas.
  534.  
  535. Copyright (c) 1995-98 Gurusamy Sarathy.  All rights reserved.
  536.  
  537. Copyright (c) 1998 Raphael Manfredi.
  538.  
  539. Copyright (c) 2002 Josh Chamas, Chamas Enterprises Inc.
  540.  
  541. This program is free software; you can redistribute it and/or
  542. modify it under the same terms as Perl itself.
  543.  
  544. =head1 VERSION
  545.  
  546. Version 2.01    07 July 2002
  547.  
  548. =head1 SEE ALSO
  549.  
  550. perl(1), perltie(1), perlfunc(1), Data::Dumper(3), FreezeThaw(3), Storable(3).
  551.  
  552. =cut
  553.